/*
 * Copyright (c) 2009 Bogong (www.bogong.dk)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <windows.h>
#include <httpext.h>
#include "../DumpLogCommon/Common.h"


// Debug zones 
#define ZONE_DUMPLOG_DBG               DEBUGZONE(0)
#define ZONE_DUMPLOG_WARNING           DEBUGZONE(14)
#define ZONE_DUMPLOG_ERROR             DEBUGZONE(15)

// Debug zone masks
#define ZONEMASK_DBG                   (1 << 0)
#define ZONEMASK_WARNING               (1 << 14)
#define ZONEMASK_ERROR                 (1 << 15)

// Max size of page buffer
#define PAGE_BUFFER_SIZE               (100000)

// Debug settings */
DBGPARAM dpCurSettings = 
{
    //Process or module name
    TEXT("DumpLogIsApi"), 

    { // Descriptive names for 16 zones
        TEXT("Debug"),TEXT(""),TEXT(""),TEXT(""),
            TEXT(""),TEXT(""),TEXT(""),TEXT(""),
            TEXT(""),TEXT(""),TEXT(""),TEXT(""),
            TEXT(""),TEXT(""),TEXT("Warnings"), TEXT("Errors")
    },
    // Zones enabled by default
    (ZONEMASK_WARNING | ZONEMASK_ERROR)
}; 

// Pointer to page buffer
static char *g_pszPage = NULL;

// Current offset in page buffer
static DWORD g_dwOffset = 0;


// Entry point called when a process hooks up to the DLL
BOOL APIENTRY DllMain(
                      HANDLE hinstDLL,        /*!< Handle to the dll */
                      DWORD dwReason,         /*!< Reason for invocation */
                      void *pReserved         /*!< Unused */
                      )
{
    switch (dwReason)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls((HMODULE)hinstDLL);
        DEBUGREGISTER((HMODULE)hinstDLL);
        RETAILREGISTERZONES((HMODULE)hinstDLL);
        break;
    case DLL_PROCESS_DETACH:
        DEBUGMSG(ZONE_DUMPLOG_DBG, (TEXT("DLL_PROCESS_DETACH")));
        break;
    }
    DEBUGMSG(ZONE_DUMPLOG_DBG,(TEXT("DumpLogIsApi DllMain\r\r\n")));
    return TRUE;
}


// Send a text page to the browser
static void SendTextPage(LPEXTENSION_CONTROL_BLOCK pECB, char *pszText)
{
    char szHeaders[128];
    DWORD dwLen = strlen(pszText);

    memset(szHeaders, 0, sizeof(szHeaders));
    sprintf_s(szHeaders, sizeof(szHeaders), "Content-length: %d\r\n\r\n", dwLen);
    pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, 0,0, (LPDWORD) szHeaders);
    pECB->WriteClient(pECB->ConnID, (LPVOID)pszText, &dwLen, 0);
}


// Send an error to the browser
static void SendErrorPage(LPEXTENSION_CONTROL_BLOCK pECB, char *pszText)
{
    char szErrorPage[512];
    memset(szErrorPage, 0, sizeof(szErrorPage));
    sprintf_s(szErrorPage, sizeof(szErrorPage), "<h1>Error</h1><p>%s</p>", pszText);
    SendTextPage(pECB, szErrorPage);
}


// Add a single log line to the page buffer (callback from common dumplog code)
static void PrintLogLine(wchar_t *pszLine, void *pArg)
{
    sprintf_s(&g_pszPage[g_dwOffset], PAGE_BUFFER_SIZE - g_dwOffset, "%S\n", pszLine);
    g_dwOffset += wcslen(pszLine) + 1;
}


// Standard API to get ISAPI version
extern "C" BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO* pVer) 
{
    DEBUGMSG(ZONE_DUMPLOG_DBG, (TEXT("DumpLogIsApi: GetExtensionVersion\r\n")));
    DEBUGMSG(ZONE_DUMPLOG_DBG, (TEXT("DumpLogIsApi: build time %S %S\r\n"), __DATE__, __TIME__ ));
    pVer->dwExtensionVersion = HSE_VERSION;
    return TRUE;
}


// Process a single request from the browser
extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK pECB) 
{
    HANDLE hFile = INVALID_HANDLE_VALUE;
    wchar_t szInFile[MAX_PATH];
    HKEY hKey;
    DWORD dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCWSTR)CE_LOG_FILE_PATH, 0, 0, &hKey);

    DEBUGMSG(ZONE_DUMPLOG_DBG, (TEXT("DumpLogIsApi: HttpExtensionProc\r\n")));

    if (ERROR_SUCCESS == dwResult)
    {
        DWORD dwSize = sizeof(szInFile);
        DWORD dwType = REG_SZ;
        dwResult = RegQueryValueEx(hKey, L"FileName", NULL, &dwType, (LPBYTE)szInFile, &dwSize);
        RegCloseKey(hKey);
        if (dwResult != ERROR_SUCCESS)
        {
            SendErrorPage(pECB, "Failed to read log file name from registry");
        }
    }
    else
    {
        SendErrorPage(pECB, "Failed to open registry key");
    }
    
    hFile = CreateFile(szInFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
    if (hFile != INVALID_HANDLE_VALUE) 
    {
        g_pszPage = (char *)malloc(PAGE_BUFFER_SIZE);
        if (g_pszPage != NULL)
        {
            wchar_t szHeaderText[MAX_PATH];

            memset(g_pszPage, 0, PAGE_BUFFER_SIZE);
            g_dwOffset = 0;
            swprintf_s(szHeaderText, _countof(szHeaderText), L"Windows CE DumpLog 0.1 (Compile time: %S %S)\n"
                                                             L"Copyright (C) 2009 by Bogong (www.bogong.dk)\n"
                                                             , __DATE__, __TIME__);
            PrintLogLine(szHeaderText, NULL);
            ProcessLogFile(hFile, PrintLogLine, NULL);
            SendTextPage(pECB, g_pszPage);
            free(g_pszPage);
        }
        else
        {
            SendErrorPage(pECB, "Failed to allocate memory");
        }
        CloseHandle(hFile);
    }
    else
    {
        SendErrorPage(pECB, "Failed to open log file");
    }

    return HSE_STATUS_SUCCESS;
}
